﻿using NLog;
using Scpi.Core.Business;
using Scpi.GWInstek.Controler;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml.Serialization;

namespace TestGWApp
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public static readonly string DeviceConfParamsUri = "./DeviceInfo.xml";
        public static Logger logger = LogManager.GetCurrentClassLogger();
        public event PropertyChangedEventHandler PropertyChanged;

        private GwPWSControler gwControler = null;
        private CancellationTokenSource cancellation = null;

        public int PowerOnCnt { get => _powerOnCnt;
            set
            {
                _powerOnCnt = value;
                if(PropertyChanged!=null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("PowerOnCnt"));
                }
            } 
        }
        private int _powerOnCnt = 0;

        private int _outputsecond;

        public int OutputSecond
        {
            get { return _outputsecond; }
            set 
            { _outputsecond = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("OutputSecond"));
                    TextBox_LostFocus();
                }
            }
        }

        private int _testCount;

        public int TestCount
        {
            get { return _testCount; }
            set { _testCount = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("TestCount"));
                    TextBox_LostFocus();
                }
            }
        }

        private int _runCount;

        public int RunCount
        {
            get { return _runCount; }
            set
            {
                _runCount = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("RunCount"));
                }
            }
        }

        private int _delaySecond;

        public int DelaySecond
        {
            get { return _delaySecond; }
            set { _delaySecond = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("DelaySecond"));
                    TextBox_LostFocus();
                }
            }
        }

        private int _dutyDuartion;

        public int DutyDuartion
        {
            get { return _dutyDuartion; }
            set {
                _dutyDuartion = value;
                if(PropertyChanged !=null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("DutyDuartion"));
                }
            }
        }

        private string _TargetAddress;

        public string TargetAddress
        {
            get { return _TargetAddress; }
            set { _TargetAddress = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("TargetAddress"));
                }
            }
        }

        private double _outputCurrent;

        public double OutputCurrent
        {
            get { return _outputCurrent; }
            set { _outputCurrent = value;
                if (PropertyChanged!=null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("OutputCurrent"));
                }
            }
        }

        private double _outputVoltage;

        public double OutputVoltage
        {
            get { return _outputVoltage; }
            set { _outputVoltage = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("OutputVoltage"));
                }
            }
        }

        private double _outputPower;

        public double OutputPower
        {
            get { return _outputPower; }
            set
            {
                _outputPower = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("OutputPower"));
                }
            }
        }

        private Timer _monitorTimer;

        public MainWindow()
        {
            InitializeComponent();
            buttonPowerOff.IsEnabled = false;
            DataContext = this;
        }

        private void InitMonitorTimer()
        {
            _monitorTimer = new Timer(new TimerCallback(MonitorAsync));

            _monitorTimer.Change(1000, 2000);
        }

        private void InitalConnectItem()
        {
            if (!File.Exists(DeviceConfParamsUri))
            {
                logger.Warn($"无法打开 {DeviceConfParamsUri}配置文件");
                return;
            }

            using (Stream stream=new FileStream(DeviceConfParamsUri, FileMode.Open))
            {
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(TargetInfo));
                var targetInfo = xmlSerializer.Deserialize(stream) as TargetInfo;

                gwControler = ControlerBuilder.BuildGwPWSCtr(targetInfo);
                TargetAddress = targetInfo.CommParam.GetURI();
            }
        }

        private async void MonitorAsync(object state)
        {
            var result = await gwControler?.ControlMeasureOutput();
            if (result)
            {
                OutputCurrent = (float)gwControler.OutputCurrent;
                OutputVoltage = (float)gwControler.OutputVoltage;
            }
        }

        private async void Button_ClickAsync(object sender, RoutedEventArgs e)
        {
            string ipaddrstr = textBoxIpAddr.Text;
            bool isAddrChanged = false;

            if(gwControler!=null)
            {
                if(ipaddrstr != gwControler.DeviceInfo.CommParam.GetURI())
                {
                    isAddrChanged = true;
                    gwControler.Dispose();
                }
            }
            else
            {
                isAddrChanged = true;
            }

            if(isAddrChanged)
            {
                gwControler = ControlerBuilder.BuildGwPWSCtr(ipaddrstr, ipaddrstr);

                using (var stream = new FileStream(DeviceConfParamsUri, FileMode.OpenOrCreate))
                {
                    XmlSerializer xmlSerializer = new XmlSerializer(typeof(TargetInfo));
                    xmlSerializer.Serialize(stream, gwControler.DeviceInfo );
                }
            }

            var Result=await gwControler.ConnectRemoteAsync();
            if(!Result)
            {
                logger.Warn($"链接远端（{ipaddrstr}）失败");
                textBlockConnect.Text = "连接失败";
            }
            else
            {
                logger.Info($"链接远端（{ipaddrstr}）成功");
                textBlockConnect.Text = "通信正常";

                InitMonitorTimer();
            }
        }

        private void buttonDisconn_Click(object sender, RoutedEventArgs e)
        {
            _monitorTimer?.Dispose();
            gwControler?.Dispose();
            logger.Warn($"链接远端断开");
            textBlockConnect.Text = "连接断开";
        }

        private async void buttonPowerOn_Click(object sender, RoutedEventArgs e)
        {
            await OutputCtrl();
        }

        private async Task OutputCtrl()
        {
            var result = await gwControler.EnablePowerOutAsync();
            if (result)
            {
                await Dispatcher.BeginInvoke(new Action(() =>
                {
                    buttonPowerOn.IsEnabled = false;
                    buttonPowerOff.IsEnabled = true;
                }));
                PowerOnCnt++;
                logger.Info($"{gwControler.DeviceInfo.Name} PowerOn Ok! Cnt={PowerOnCnt}");
            }
            else
            {
                logger.Warn($"{gwControler.DeviceInfo.Name} PowerOn Error!");
            }
        }

        private async void buttonPowerOff_Click(object sender, RoutedEventArgs e)
        {
            await DisOutputCtrl();
        }

        private async Task DisOutputCtrl()
        {
            var result = await gwControler.DisablePowerOutAsync();

            if (result == true)
            {

                await Dispatcher.BeginInvoke(new Action(() =>
                {
                    buttonPowerOn.IsEnabled = true;
                    buttonPowerOff.IsEnabled = false;
                }));
                
                logger.Info($"{gwControler.DeviceInfo.Name} PowerOff Ok!");
            }
            else
            {
                logger.Warn($"{gwControler.DeviceInfo.Name} PowerOff Error!");
            }
        }

        private void buttonClearCnt_Click(object sender, RoutedEventArgs e)
        {
            PowerOnCnt = 0;
        }

        private void Window_Closing(object sender, CancelEventArgs e)
        {
            logger.Info($"All Power Cnt={PowerOnCnt}");
            gwControler?.Dispose();
        }

        private void StartTestTask_Click(object sender, RoutedEventArgs e)
        {
            cancellation = new CancellationTokenSource();
            Task.Factory.StartNew(RepeatTestTask, cancellation.Token);
        }

        private void StopTestTask_Click(object sender, RoutedEventArgs e)
        {
            cancellation?.Cancel();
            logger.Info($"Stop Repeat Task {cancellation?.IsCancellationRequested}");

            cancellation?.Dispose();
        }

        public async void RepeatTestTask()
        {
            logger.Info($"Start Repeat Test (PowerOff {DelaySecond}s: PowerOn {OutputSecond}s testCnt:{TestCount})");
            for (RunCount = 0; RunCount < TestCount; RunCount++)
            {
                await Task.Delay(DelaySecond * 1000);
                if((bool)(cancellation?.IsCancellationRequested))
                {
                    logger.Info("Task cannel");
                    return;
                }
                await OutputCtrl();
                await Task.Delay(OutputSecond * 1000);
                if ((bool)(cancellation?.IsCancellationRequested))
                {
                    logger.Info("Task cannel");
                    return;
                }
                await DisOutputCtrl();
            }
            logger.Info("Start Repeat Test Complited");
        }

        private void TextBox_LostFocus()
        {
            DutyDuartion = (OutputSecond + DelaySecond) * TestCount;
        }
    }
}
